package com.maimao.search.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.maimao.core.constant.Constants;
import com.maimao.core.model.resp.Result;
import com.maimao.model.goods.Brand;
import com.maimao.model.goods.Category;
import com.maimao.model.goods.SpecDetails;
import com.maimao.model.goods.enums.FormType;
import com.maimao.search.client.BrandClient;
import com.maimao.search.client.CateClient;
import com.maimao.search.client.SpecDetailClient;
import com.maimao.search.model.goods.EsGoods;
import com.maimao.search.model.goods.GoodsSearch;
import com.maimao.search.model.goods.SearchPageResult;
import com.maimao.search.model.goods.SearchParam;
import com.maimao.search.utils.EsUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/*
搜索的查询语句
GET mm_goods/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "key": "手机"
          }
        }
      ],
      "filter": {
          "bool": {
            "must":[
               {
                 "terms": {
                    "searchParams.CPU型号.keyword":   ["骁龙750G","麒麟990 5G"]
                 }
               }
            ],
          "filter":{
            "match": {
              "searchParams.特殊功能": "超大字体 暂无" //手动输入类型的参数
            }
          }
        }
      }
    }
  }
}
 */

/**
 * @author MaoLin Wang
 * @date 2020/12/26 8:37 下午
 */
@Service
public class GoodsSearchService {


    @Value("${maimao.es.goods.index}")
    private String index;
    @Value("${maimao.es.goods.type}")
    private String type;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private BrandClient brandClient;
    @Autowired
    private CateClient cateClient;

    @Autowired
    private SpecDetailClient specDetailClient;

    @Autowired
    private EsUtil esUtil;

    private final String[] INCLUDE_FIELDS = new String[]{"id", "shopId", "shopName", "goodsSkus", "createTime", "subName"};

    private static final List EMPTY_LIST = Lists.newArrayList();

    /**
     * 搜索商品
     *
     * @param goodsSearch
     * @return
     */
    /*
      搜索过滤规格聚合算法：
        GET mm_goods/_search
            {
                "query": {
                    "bool": {
                        "must": [
                            {
                                "match": {
                                    "key": "手机"
                                }
                            }
                        ],
                        "filter": {
                            "bool": {
                                "must": [
                                    {
                                        "terms": {
                                            "searchParams.CPU型号.keyword": [
                                                "骁龙750G",
                                                "麒麟990 5G"
                                            ]
                                        }
                                    }
                                ],
                                "filter": {
                                    "match": {
                                        "searchParams.特殊功能": "超大字体 暂无"
                                    }
                                }
                            }
                        }
                    }
                },
                "aggs": {
                    "brandIds": {
                        "terms": {
                            "field": "brandId"
                        }
                    },
                    "AGG_CID3": {
                        "terms": {
                            "field": "cid3"
                        }
                    },
                    "分辨率": {
                        "terms": {
                            "field": "searchParams.分辨率.keyword"
                        }
                    }
                }
            }
     */
    public SearchPageResult<EsGoods> searchGoods(GoodsSearch goodsSearch) {
        String key = goodsSearch.getKey();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isEmpty(goodsSearch.getKey())) {
            //关键词为空就根据分类查询
            boolQueryBuilder.must(QueryBuilders.termQuery("cid3", goodsSearch.getCid3()));
        } else {
            boolQueryBuilder.must(QueryBuilders.matchQuery("key", key).operator(Operator.AND));
        }
        List<SearchParam> filterOptions = goodsSearch.getFilterOptions();
        //添加过滤
        if (filterOptions != null && filterOptions.size() > 0) {
            BoolQueryBuilder filterBoolQueryBuilder = new BoolQueryBuilder();
            for (SearchParam searchParam : filterOptions) {
                String term = "";
                String name = searchParam.getName();
                Boolean text = searchParam.getText();
                if (name.equals("brandId")) {
                    term = "brandId";
                } else if (name.equals("cid3")) {
                    term = "cid3";
                } else if (text != null && text) {
                    term = "searchParams." + name;
                } else {
                    term = "searchParams." + name + ".keyword";
                }
                if (text != null && text) {
                    //参数的formType为TEXT（即要求用户自己输入的规格）时，需要按空格分隔取值进行match过滤
                    filterBoolQueryBuilder.filter(QueryBuilders.matchQuery(term, StringUtils.join(searchParam.getValues(), Constants.BLANK)));
                } else {
                    //否则基于terms查询
                    if (searchParam.getValues() != null && searchParam.getValues().size() > 0) {
                        filterBoolQueryBuilder.must(QueryBuilders.termsQuery(term, searchParam.getValues()));
                    }
                }
            }
            boolQueryBuilder.filter(filterBoolQueryBuilder);
        }

        String brandAgg = "AGG_BRAND";
        String categoryAgg = "AGG_CATEGORY";
        //聚合品牌和分类
        TermsAggregationBuilder brandAggBuilder = AggregationBuilders.terms(brandAgg).field("brandId");
        TermsAggregationBuilder categoryAggBuilder = AggregationBuilders.terms(categoryAgg).field("cid3");

        String sortField = "priceList";
        if (StrUtil.isNotEmpty(goodsSearch.getSortField())) {
            sortField = goodsSearch.getSortField();
        }
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .from((goodsSearch.getPage() - 1) * goodsSearch.getSize())
                .size(goodsSearch.getSize())
                .fetchSource(INCLUDE_FIELDS, null)
                .query(boolQueryBuilder)
                .aggregation(brandAggBuilder)
                .sort(sortField, SortOrder.DESC)
                .aggregation(categoryAggBuilder);
        SearchRequest searchRequest = new SearchRequest(index)
                .types(type)
                .source(searchSourceBuilder);
        JSONArray jsonArray = new JSONArray();
        SearchResponse searchResponse = esUtil.search(searchRequest, jsonArray);
        Map<String, List<ParsedLongTerms.ParsedBucket>> brandCateAggMap = esUtil.getAggLongBuckets(searchResponse);
        //获取品牌和分类的桶
        List<ParsedLongTerms.ParsedBucket> brandBuckets = brandCateAggMap.get(brandAgg);
        List<ParsedLongTerms.ParsedBucket> categoryBuckets = brandCateAggMap.get(categoryAgg);
        List<Long> brandIds = new ArrayList<>(brandBuckets.size());
        List<Integer> categoryIds = new ArrayList<>(categoryBuckets.size());
        for (ParsedLongTerms.ParsedBucket brandBucket : brandBuckets) {
            brandIds.add(brandBucket.getKeyAsNumber().longValue());
        }
        for (ParsedLongTerms.ParsedBucket categoryBucket : categoryBuckets) {
            categoryIds.add(categoryBucket.getKeyAsNumber().intValue());
        }
        Result<List<Brand>> brandsRes = brandClient.selectByIdBatch(brandIds);
        Result<List<Category>> cateRes = cateClient.selectByIds(categoryIds);


        List<EsGoods> esGoodsList = jsonArray.toJavaList(EsGoods.class);
        SearchPageResult<EsGoods> searchPageResult = new SearchPageResult<>(esGoodsList, searchResponse.getHits().totalHits);
        searchPageResult.setBrandList(brandsRes.getData() == null ? EMPTY_LIST : brandsRes.getData());
        searchPageResult.setCategoryList(cateRes.getData() == null ? EMPTY_LIST : cateRes.getData());
        searchPageResult.setSearchParamList(searchPageResult.getCategoryList().size() > 0 ? getSearchParamList(boolQueryBuilder, searchPageResult.getCategoryList()) : EMPTY_LIST);

        return searchPageResult;

    }

    /**
     * 获取搜索参数的聚合结果
     *
     * @param queryBuilder 搜索条件
     * @param categoryList 所有分类
     */
    private List<SearchParam> getSearchParamList(QueryBuilder queryBuilder, List<Category> categoryList) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .size(0)
                .query(queryBuilder);
        List<Integer> cids = categoryList.stream().map(Category::getId).collect(Collectors.toList());
        Result<List<SpecDetails>> paramsRes = specDetailClient.findSearchSpecByCidBatch(cids);

        if (paramsRes != null) {
            List<SpecDetails> params = paramsRes.getData();
            if (params != null && params.size() > 0) {
                Map<String, List<SpecDetails>> paramNameMap = params.stream().collect(Collectors.groupingBy(SpecDetails::getName));
                for (SpecDetails param : params) {
                    //对分类下的搜索参数进行聚合
                    searchSourceBuilder.aggregation(AggregationBuilders.terms(param.getName()).field("searchParams." + param.getName() + ".keyword"));
                }
                SearchRequest searchRequest = new SearchRequest(index)
                        .types(type)
                        .source(searchSourceBuilder);

                SearchResponse searchResponse = esUtil.search(searchRequest);
                Map<String, List<ParsedStringTerms.ParsedBucket>> aggStringBuckets = esUtil.getAggStringBuckets(searchResponse);

                List<SearchParam> searchParamList = Lists.newArrayListWithCapacity(aggStringBuckets.size());
                aggStringBuckets.entrySet().stream().forEach(bucketEntry -> {
                    List<String> values = bucketEntry.getValue().stream().map(ParsedStringTerms.ParsedBucket::getKeyAsString).collect(Collectors.toList());
                    List<SpecDetails> specDetailsList = paramNameMap.get(bucketEntry.getKey());

                    boolean text = false;
                    for (SpecDetails specDetails : specDetailsList) {
                        if (specDetails.getFormType().equals(FormType.TEXT.getName())) {
                            text = true;
                            HashSet<String> hashValues = Sets.newHashSet();
                            for (String value : values) {
                                String[] split = StringUtils.split(value, "，");
                                if (split.length > 0) {
                                    hashValues.addAll(Arrays.asList(split));
                                } else if ((split = StringUtils.split(value, Constants.BLANK)).length > 0) {
                                    hashValues.addAll(Arrays.asList(split));
                                } else if ((split = StringUtils.split(value, Constants.COMMA)).length > 0) {
                                    hashValues.addAll(Arrays.asList(split));
                                }
                            }
                            values = Lists.newArrayList(hashValues);
                            break;
                        }
                    }
                    searchParamList.add(new SearchParam(bucketEntry.getKey(), text, values));
                });
                return searchParamList;

            }
        }

        return EMPTY_LIST;


    }

    /**
     * 搜索补全
     *
     * @param key 搜索内容
     * @return 自动补全提示
     */
    public List<String> searchSuggestions(String key) {
        SearchRequest searchRequest = new SearchRequest(index);
        searchRequest.types(type);

        SuggestBuilder suggestBuilder = new SuggestBuilder();
        String suggestName = "KEY_SUGGESTION";
        CompletionSuggestionBuilder suggestionsBuilder = SuggestBuilders.completionSuggestion("suggestions").prefix(key).skipDuplicates(true);
        suggestBuilder.addSuggestion(suggestName, suggestionsBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //不返回文档数据
        searchSourceBuilder.fetchSource(null, new String[]{"*"});
        searchSourceBuilder.suggest(suggestBuilder);
        searchRequest.source(searchSourceBuilder);

        List<String> suggestionList = new ArrayList<>();
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> suggestResult = response.getSuggest().getSuggestion(suggestName).getEntries();
        if (suggestResult != null && suggestResult.size() > 0) {
            for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> suggest : suggestResult) {
                List<? extends Suggest.Suggestion.Entry.Option> options = suggest.getOptions();
                if (options != null && options.size() > 0) {
                    for (Suggest.Suggestion.Entry.Option option : options) {
                        //
                        suggestionList.add(option.getText().string());
                    }
                }
            }
        }
        return suggestionList;
    }

    public static void main(String[] args) {
        /*ArrayList<Brand> brands = Lists.newArrayListWithCapacity(10);
        for (int i = 0; i < 10; i++) {
            Brand brand = new Brand();
            brand.setId((long) i);
            brand.setName(i + "");
            brands.add(brand);
        }
        Brand brand = new Brand();
        brand.setId(2L);
        brand.setName("lala");
        brands.add(brand);
        Map<Long, ArrayList<Brand>> collect = brands.stream().collect(Collectors.toMap(Brand::getId, Lists::newArrayList, (v1, v2) -> {
            v2.addAll(v1);
            return v2;
        }));
        System.out.println(collect);*/
        Integer code = 3;
        int a = 3;
        System.out.println(code.equals(a));
    }
}
/*
自动补全结果格式：
"suggest" : {
    "KEY_SUGGESTION" : [
      {
        "text" : "米家",
        "offset" : 0,
        "length" : 2,
        "options" : [
          {
            "text" : "米家",
            "_index" : "mm_goods",
            "_type" : "_doc",
            "_id" : "1341426379399954433",
            "_score" : 10.0,
            "_source" : {

            }
          }
        ]
      }
    ]
  }
 */